/* File name      :  nfivi.c
 * Author         :  Wentao Shang
 * 
 * Contents       : 
 *     This file defines the top module for 'nfivi' project, including 
 *     netfilter hooks for packets capture, 'fops' structure to register
 *     'nfivi' character device, and module init/exit functions which
 *     perform hook/device registration/unregistration work. This module
 *     will be last installed when running './control start' command.
 *
 */

#ifndef __KERNEL__
#  define __KERNEL__
#endif

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/netfilter.h>
#include <linux/netfilter_ipv6.h>

#include "nfivi_io.h"
#include "nfivi_xmit.h"
#include "nfivi_map.h"

/* character device register structure */
struct file_operations nfivi_fops = {
	.owner = THIS_MODULE,
	.ioctl = device_ioctl,
	.open = device_open,
	.release = device_release,
};

/* hook functions for netfiler */

/* hook for inflow packets */
unsigned int nfivi_v6in_hook( unsigned int hooknum, struct sk_buff *skb,
						const struct net_device *in, const struct net_device *out,
						int (*okfn)(struct sk_buff *) )
{	
	if( port_map_in(skb) == 0 )
		return NF_DROP;
	else
		return NF_ACCEPT;
}

/* hook for outflow packets */
unsigned int nfivi_v6out_hook( unsigned int hooknum, struct sk_buff *skb,
						const struct net_device *in, const struct net_device *out,
						int (*okfn)(struct sk_buff *) )
{
	if( port_map_out(skb) == 0 )
		return NF_DROP;
	else
		return NF_ACCEPT;
}

/* hook struct for inflow packets */
static struct nf_hook_ops port_map_in_ops = { 
	{ NULL, NULL }, 
	nfivi_v6in_hook, 
	THIS_MODULE,
	PF_INET6, 
	NF_IP6_PRE_ROUTING, 
	NF_IP6_PRI_NAT_DST 
};

/* hook struct for outflow packets */
static struct nf_hook_ops port_map_out_ops = { 
	{ NULL, NULL }, 
	nfivi_v6out_hook, 
	THIS_MODULE,
	PF_INET6, 
	NF_IP6_LOCAL_OUT, 
	NF_IP6_PRI_NAT_SRC
};


static int init_map(void)
{
	int ret_val;
	
	ret_val = register_chrdev(MAJOR_NUM, DEVICE_NAME, &nfivi_fops);
	
	if (ret_val < 0) {
		printk ("register_chrdev failed with %d\n", ret_val);
		return ret_val;
	}
	
	printk("nfivi_fops register success!\n");
	
	nf_register_hook(&port_map_in_ops);
	nf_register_hook(&port_map_out_ops);
	printk("nfivi netfilter hooks register success!\n");
	
	init_map_list(&MapList);
	printk("MapList init success!\n");
	
	return 0;
}
module_init(init_map);

static void exit_map(void)
{
	nf_unregister_hook(&port_map_in_ops);
	nf_unregister_hook(&port_map_out_ops);
	printk("nfivi netfilter hooks unregister success!\n");
	
	free_map_list(&MapList);
	printk("MapList free success!\n");
	
	unregister_chrdev(MAJOR_NUM, DEVICE_NAME);
	printk("nfivi_fops unregister success!\n");
}
module_exit(exit_map);

MODULE_LICENSE("GPL");

